package com.dsg.service.oil.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dsg.common.constants.DsgStatusConstant;
import com.dsg.common.constants.MessageConstants;
import com.dsg.common.dto.AjaxResult;
import com.dsg.common.security.SystemAuthorizingUser;
import com.dsg.common.util.SingletonLoginUtils;
import com.dsg.common.util.UUIDGenerator;
import com.dsg.common.util.toolbox.CollectionUtil;
import com.dsg.common.util.toolbox.DateUtil;
import com.dsg.common.util.toolbox.StringUtil;
import com.dsg.dao.oil.DsgOilDataMapper;
import com.dsg.entity.account.DsgAccountCus;
import com.dsg.entity.apply.DsgApplyCar;
import com.dsg.entity.apply.DsgApplyCard;
import com.dsg.entity.apply.DsgApplyCus;
import com.dsg.entity.apply.DsgApplyDiscount;
import com.dsg.entity.bank.DsgBankDetail;
import com.dsg.entity.oil.*;
import com.dsg.service.DsgServiceImpl;
import com.dsg.service.account.IDsgAccountCusService;
import com.dsg.service.account.IDsgAccountTradeService;
import com.dsg.service.apply.IDsgApplyCarService;
import com.dsg.service.apply.IDsgApplyCardService;
import com.dsg.service.apply.IDsgApplyCusService;
import com.dsg.service.apply.IDsgApplyDiscountService;
import com.dsg.service.oil.*;
import com.dsg.support.LeveldbAccess;
import com.dsg.util.DateUtils;
import com.dsg.util.DsgUtils;
import com.dsg.util.RRException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 入油数据汇总 服务实现类
 * </p>
 *
 * @author system
 * @since 2020-06-30
 */
@Service
@Slf4j
public class DsgOilDataServiceImpl extends DsgServiceImpl<DsgOilDataMapper, DsgOilData> implements IDsgOilDataService {

    @Autowired
    private DsgOilDataMapper dsgOilDataMapper;
    @Autowired
    private IDsgOilDataDetailService dsgOilDataDetailService;
    @Autowired
    private IDsgOilProductService dsgOilProductService;
    @Autowired
    private IDsgApplyCarService dsgApplyCarService;
    @Autowired
    private IDsgApplyCardService dsgApplyCardService;
    @Autowired
    private IDsgOilStationService dsgOilStationService;
    @Autowired
    private IDsgApplyCusService dsgApplyCusService;
    @Autowired
    private IDsgAccountCusService dsgAccountCusService;
    @Autowired
    private IDsgOilDoubtListService dsgOilDoubtListService;
    @Autowired
    private IDsgApplyDiscountService dsgApplyDiscountService;
    @Autowired
    private IDsgAccountTradeService dsgAccountTradeService;
    @Autowired
    private LeveldbAccess leveldbAccess;
    @Autowired
    private DsgUtils dsgUtils;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateHandleStatus(String idList) {
        if (StringUtil.isEmpty(idList)) {
            throw new RRException("主鍵不能為空！");
        }
        DsgOilData dsgOilData = new DsgOilData();
        dsgOilData.setHandleStatus(DsgStatusConstant.IS_DEFAULT_ONE);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.in("OID", Arrays.asList(idList.split(",")));
        dsgOilDataMapper.update(dsgOilData, queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult checkData(DsgOilData dsgOilData) {
        if (StringUtil.isEmpty(dsgOilData.getOid())) {
            throw new RRException("主鍵不能為空！");
        }
        AjaxResult ajaxResult = new AjaxResult(MessageConstants.SSO_STATUS_FAIL);
        List<DsgOilData> dsgOilDataList = this.listByIds(Arrays.asList(dsgOilData.getOid().split(",")));
        List<String> keyList = new ArrayList<>();
        try {
            if (CollectionUtil.isEmpty(dsgOilDataList)) {
                throw new RRException("入油匯總數據不存在！");
            } else {
                Date date = new Date();
                //登录用户信息
                SystemAuthorizingUser sysUser = SingletonLoginUtils.getSystemUser();
                //錯誤信息
                List<String> errorList = new ArrayList<>();
                //入油匯總OID
                String oid = UUIDGenerator.getUUID();
                //企業油產品緩存 productNo
                QueryWrapper<DsgOilProduct> dopQueryWrapper = new QueryWrapper();
                dopQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                List<DsgOilProduct> dsgOilProductList = dsgOilProductService.list(dopQueryWrapper);
                dsgOilProductList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgOilProduct.class.getSimpleName(), I.getProductNo());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgOilProductList.clear();
                //油咭緩存 cardNo
                QueryWrapper<DsgApplyCard> dacQueryWrapper = new QueryWrapper();
                dacQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                dacQueryWrapper.isNotNull("CARD_NO");
                List<DsgApplyCard> dsgApplyCardList = dsgApplyCardService.list(dacQueryWrapper);
                Map<String, List<DsgApplyCard>> dsgApplyCardMap = dsgApplyCardList.stream().collect(Collectors.groupingBy(I -> I.getCardNo()));
                for (String key : dsgApplyCardMap.keySet()) {
                    List<DsgApplyCard> dsgApplyCards = dsgApplyCardMap.get(key);
                    key = leveldbAccess.genCacheKey(oid, DsgApplyCard.class.getSimpleName(), key);
                    leveldbAccess.put(key, dsgApplyCards);
                    keyList.add(key);
                }
                dsgApplyCardList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgApplyCard.class.getSimpleName(), I.getCardNo(), I.getCardStatus());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgApplyCardList.clear();
                //車牌对应油咭號 cardNo
                DsgApplyCar queryDsgApplyCar = new DsgApplyCar();
                queryDsgApplyCar.setEntCode(sysUser.getOrgCode());
                queryDsgApplyCar.setCardStatus(DsgApplyCard.AppStatus.inForce.getCode());
                List<DsgApplyCar> dsgApplyCarDtoList = dsgApplyCarService.selectDsgApplyCarAndCard(queryDsgApplyCar);
                dsgApplyCarDtoList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgApplyCar.class.getSimpleName(), DsgApplyCard.class.getSimpleName(), I.getCardNo());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgApplyCarDtoList.clear();
                //車輛緩存 carNo
                QueryWrapper<DsgApplyCar> carQueryWrapper = new QueryWrapper();
                carQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                List<DsgApplyCar> dsgApplyCarList = dsgApplyCarService.list(carQueryWrapper);
                dsgApplyCarList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgApplyCar.class.getSimpleName(), I.getCarNo());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgApplyCarList.clear();
                //油站信息緩存 stationId
                QueryWrapper<DsgOilStation> dosQueryWrapper = new QueryWrapper();
                dosQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                dosQueryWrapper.eq("STATION_STATUS", DsgOilStation.AppStatus.takeEffect.getCode());
                List<DsgOilStation> dsgOilStationList = dsgOilStationService.list(dosQueryWrapper);
                dsgOilStationList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgOilStation.class.getSimpleName(), I.getStationId());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgOilStationList.clear();
                //客戶資料 oid
                QueryWrapper<DsgApplyCus> cusQueryWrapper = new QueryWrapper();
                cusQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                List<DsgApplyCus> dsgApplyCusList = dsgApplyCusService.list(cusQueryWrapper);
                dsgApplyCusList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgApplyCus.class.getSimpleName(), I.getOid());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgApplyCusList.clear();
                //客戶總賬 cusNo
                QueryWrapper<DsgAccountCus> accountQueryWrapper = new QueryWrapper();
                accountQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                List<DsgAccountCus> dsgAccountCusList = dsgAccountCusService.list(accountQueryWrapper);
                dsgAccountCusList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgAccountCus.class.getSimpleName(), I.getCusNo());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgAccountCusList.clear();
                //折扣資料 cardId,cusNo
                QueryWrapper<DsgApplyDiscount> dadQueryWrapper = new QueryWrapper();
                dadQueryWrapper.select("CARD_NO,max(DIS_LIMIT) as disLimit,max(CHEEP_AMOUNT) as CHEEP_AMOUNT,max(COSTLY_AMOUNT) as COSTLY_AMOUNT");
                dadQueryWrapper.eq("ENT_CODE", sysUser.getOrgCode());
                dadQueryWrapper.eq("DIS_STATUS", DsgApplyDiscount.AppStatus.approved.getCode());
                dadQueryWrapper.and(i -> i.in("DISCOUNT_TYPE", 2, 3).gt(true, "EFF_DATE", date).le(true, "EXP_DATE", date));
                dadQueryWrapper.or(i -> i.notIn("DISCOUNT_TYPE", 2, 3));
                dadQueryWrapper.groupBy("CARD_NO");
                List<DsgApplyDiscount> dsgApplyDiscountList = dsgApplyDiscountService.list(dadQueryWrapper);
                dsgApplyDiscountList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgApplyDiscount.class.getSimpleName(), I.getCardNo());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                dsgApplyDiscountList.clear();
                //重復數據
                DsgOilDataDetail queryDsgOilDAtaDetail = new DsgOilDataDetail();
                queryDsgOilDAtaDetail.setEntCode(sysUser.getOrgCode());
                queryDsgOilDAtaDetail.setDate(DateUtil.formatDate(date));
                queryDsgOilDAtaDetail.setYear(DsgOilDataDetail.AppStatus.year.getCode());
                List<DsgOilDataDetail> repetitionDetailList = dsgOilDataDetailService.selectRepeatList(queryDsgOilDAtaDetail);
                repetitionDetailList.forEach(I -> {
                    String key = leveldbAccess.genCacheKey(oid, DsgOilDataDetail.class.getSimpleName(), I.getTransDate(), I.getTransTime(), I.getCarNumber(), I.getCardNo());
                    leveldbAccess.put(key, I);
                    keyList.add(key);
                });
                repetitionDetailList.clear();
                //回填檢查結果
                List<DsgOilData> updateDsgOilDataList = new ArrayList<>();
                List<DsgOilDataDetail> updateDsgOilDataDetailList = new ArrayList<>();
                List<DsgOilDoubtList> doubtList = new ArrayList<>();
                for (DsgOilData dod : dsgOilDataList) {
                    //已檢測的不能重複檢測
//                    if (dod.getCheckStatus().equals(DsgOilData.AppStatus.yes.getCode())) {
//                        errorList.add(String.format("上載批次編號%s已檢測!", dod.getBatchNo()));
//                        continue;
//                    }
                    //初始化校驗結果數值
//                    dod.setAcceptNum(BigDecimal.ZERO);
//                    dod.setSuccessNum(BigDecimal.ZERO);
                    dod.setFailNum(BigDecimal.ZERO);
                    dod.setDoubtANum(BigDecimal.ZERO);
                    dod.setDoubtBNum(BigDecimal.ZERO);
                    dod.setDoubtCNum(BigDecimal.ZERO);
                    QueryWrapper<DsgOilDataDetail> detailQueryWrapper = new QueryWrapper();
                    detailQueryWrapper.eq("PID", dod.getOid());
                    detailQueryWrapper.eq("IS_ACCEPT", DsgOilDataDetail.AppStatus.temporary.getCode());
                    List<DsgOilDataDetail> dsgOilDataDetailList = dsgOilDataDetailService.list(detailQueryWrapper);
                    if (CollectionUtil.isNotEmpty(dsgOilDataDetailList)) {
                        String key = "";
                        for (DsgOilDataDetail dsgOilDataDetail : dsgOilDataDetailList) {
                            //初始化校驗結果數值
                            dsgOilDataDetail.setIsSuccess(null);
                            dsgOilDataDetail.setIsDoubt(null);
                            Map<String, String> doubtMap = new HashMap<>();
                            doubtMap.put("A", null);
                            doubtMap.put("B", null);
                            doubtMap.put("C", null);
                            /**
                             存疑A
                             */
                            if (StringUtil.isNotEmpty(dsgOilDataDetail.getCardNo())) {
                                //6系統中油咭所屬車牌，與 ESSO 數據中油咭所屬車牌有出入
                                key = leveldbAccess.genCacheKey(oid, DsgApplyCar.class.getSimpleName(), DsgApplyCard.class.getSimpleName(), dsgOilDataDetail.getCardNo());
                                DsgApplyCar dsgApplyCar = leveldbAccess.get(key);
                                if (dsgApplyCar != null) {
//                                    dsgOilDataDetail.setOwnsId(dsgApplyCar.getOwnsId());
                                    dsgOilDataDetail.setCusNo(dsgApplyCar.getCusNo());
                                    dsgOilDataDetail.setCardOid(dsgApplyCar.getCardOid());
                                    if (!dsgApplyCar.getCarNo().equals(dsgOilDataDetail.getCarNumber())) {
                                        String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
                                        doubtMap.put("A", doubt);
                                        this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), dod.getOid(), dsgOilDataDetail.getOid(), doubt, "6");
                                    }
                                }
                                //4上數時我司系統中沒有相關油咭號碼之紀錄  (未判斷是否有效卡)
                                checkDoubtA4(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            }
                            //1系統中設有折扣上/下限，上數客戶所屬折扣超越折扣上/下限 TODO
                            checkDoubtA1(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //2同日期, 同時間 , 同車牌,同 CARD NUMBER 如已於系統存在之數 據則自動拒絕接受 (其餘沒重覆的數據自動錄入至系統中)
                            checkDoubtA2(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //3如 ESSO 數據中的油費為負數
                            checkDoubtA3(dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //5我司系統有記錄現時 ESSO 生效中油站數及名稱，如 ESSO 數據中的油站名稱未在系統記錄中，會成為此存疑
                            checkDoubtA5(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //7系統中登記油種與 ESSO 數據客人入油種不同
                            checkDoubtA7(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //8如 ESSO 數據中所屬客戶的折扣正等待審批，需待完成審批後方能重 新上數
                            checkDoubtA8(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);

                            /**
                             * 存疑B
                             */
                            //1客人戶口結餘超出 10 萬
                            checkDoubtB1(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //2我司系統中客人使用油咭所屬油種折扣為 0
                            checkDoubtB2(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //3我司系統中客人行政費為 0%
                            checkDoubtB3(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //4上數 ESSO 數據中的油咭號碼於我司系統有兩位或以上客戶擁有 (如有此類情況，會以入油日期時間作準，入油時那個客戶油咭生效中則會成為上數之客戶)
                            checkDoubtB4(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            /*
                            TODO 5pump_unit_price 與 特 定 FORMULA 計算出的結果不符
                             需求不明細,導入入油數據時,單價=總價/升數 或 總價=單價*升數,所以無需校驗存異
                            */
                            checkDoubtB5(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //6上數時，上數時不是收正常數據的日子 (超越兩工作天) 提示
                            checkDoubtB6(dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //7如 A2 中的重覆交易的條件中，唯獨升數 有出入的，會掉入此處
                            checkDoubtB7(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);

                            /**
                             * 存疑C
                             */
                            //1如上數 ESSO 數據中的油咭不是生效中，需檢查存疑
                            checkDoubtC1(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //2如上數 ESSO 數據中的油咭所屬客戶狀況不是生效中，需檢查存疑
                            checkDoubtC2(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //3如油站數目與系統中生效中油站不乎，需檢查
                            checkDoubtC3(oid, dod.getOid(), doubtMap, dsgOilDataDetail, doubtList);
                            //4如某油站入油升數比以往小於 N%，需檢查會否有部份時間漏數據(N 可由相關權限同事修改) 不需要检验
                            /*5可供同事選取特定車牌／油咭編號／客戶編號
                            被選取的客戶可以個別選擇接受/處理中/拒絕
                            但必須提供證明 (上載相關附件)及會自動通知經理 不需要检验*/
                            /*6我司系統中所屬油種的牌價 TODO
                            與 ESSO 數據中 pump_unit_price
                            假如兩者不相乎需疑及產生報告給予 ESSO 檢查
                            貴油平入自動創建 EMAIL SEND TO ESSO*/
                            if (StringUtil.isNotEmpty(doubtMap.get("A"))) {
                                dod.setDoubtANum(dod.getDoubtANum().add(BigDecimal.ONE));
                                dod.setFailNum(dod.getFailNum().add(BigDecimal.ONE));
                                dsgOilDataDetail.setIsDoubt(DsgOilDataDetail.AppStatusChar.A.getCode());
                                dsgOilDataDetail.setIsSuccess(DsgOilDataDetail.AppStatus.failure.getCode());
                            } else {
                                if (StringUtil.isNotEmpty(doubtMap.get("B"))) {
                                    dod.setDoubtBNum(dod.getDoubtANum().add(BigDecimal.ONE));
                                    dod.setFailNum(dod.getFailNum().add(BigDecimal.ONE));
                                    dsgOilDataDetail.setIsDoubt(DsgOilDataDetail.AppStatusChar.B.getCode());
                                    dsgOilDataDetail.setIsSuccess(DsgOilDataDetail.AppStatus.failure.getCode());
                                } else {
                                    if (StringUtil.isNotEmpty(doubtMap.get("C"))) {
                                        dod.setDoubtCNum(dod.getDoubtCNum().add(BigDecimal.ONE));
                                        dod.setFailNum(dod.getFailNum().add(BigDecimal.ONE));
                                        dsgOilDataDetail.setIsDoubt(DsgOilDataDetail.AppStatusChar.C.getCode());
                                        dsgOilDataDetail.setIsSuccess(DsgOilDataDetail.AppStatus.failure.getCode());
                                    } else {
                                        dod.setSuccessNum(dod.getSuccessNum().add(BigDecimal.ONE));
                                        dsgOilDataDetail.setIsSuccess(DsgOilDataDetail.AppStatus.success.getCode());
                                    }
                                }
                            }
                            //無存疑修改為接受
                            if (StringUtil.isAllBlank(doubtMap.get("A"), doubtMap.get("B"), doubtMap.get("C"))) {
                                dsgOilDataDetail.setIsAccept(DsgOilDataDetail.AppStatus.accept.getCode());
                                dod.setAcceptNum(dod.getAcceptNum().add(BigDecimal.ONE));
                            }
                            updateDsgOilDataDetailList.add(dsgOilDataDetail);
                        }
                        dod.setCheckStatus(DsgOilData.AppStatus.yes.getCode());
                        updateDsgOilDataList.add(dod);
                    } else {
                        errorList.add("入油數據不存在!");
                    }
                }
                if (CollectionUtil.isNotEmpty(errorList)) {
                    StringBuffer errors = dsgUtils.genErrorMessage(errorList);
                    ajaxResult.setCode(MessageConstants.SSO_STATUS_FAIL.getCode());
                    ajaxResult.setMessage(errors.toString());
                    return ajaxResult;
                } else {
                    //回填入油匯總
                    updateBatchById(updateDsgOilDataList);
                    //回填入油明細
                    dsgOilDataDetailService.updateBatchById(updateDsgOilDataDetailList);
                    //返回信息
                    DsgOilData returnDsgOilData = new DsgOilData();
                    BigDecimal successNum = BigDecimal.ZERO;
                    BigDecimal failNum = BigDecimal.ZERO;
                    BigDecimal doubtANum = BigDecimal.ZERO;
                    BigDecimal doubtBNum = BigDecimal.ZERO;
                    BigDecimal doubtCNum = BigDecimal.ZERO;
                    List<String> oidList = new ArrayList<>();
                    for (DsgOilData oilData : updateDsgOilDataList) {
                        oidList.add(oilData.getOid());
                        successNum = successNum.add(oilData.getSuccessNum());
                        failNum = failNum.add(oilData.getFailNum());
                        doubtANum = doubtANum.add(oilData.getDoubtANum());
                        doubtBNum = doubtBNum.add(oilData.getDoubtBNum());
                        doubtCNum = doubtCNum.add(oilData.getDoubtCNum());
                    }
                    //刪除存疑記錄
                    if (CollectionUtil.isNotEmpty(updateDsgOilDataList)) {
                        QueryWrapper delQueryWrapper = new QueryWrapper();
                        delQueryWrapper.in("COL_ID", oidList);
                        dsgOilDoubtListService.remove(delQueryWrapper);
                    }
                    //存疑記錄
                    dsgOilDoubtListService.saveBatch(doubtList);
                    //存交易賬目
                    DsgBankDetail dsgBankDetail = new DsgBankDetail();
                    dsgBankDetail.setEntCode(sysUser.getOrgCode());
                    dsgBankDetail.setPidList(dsgOilData.getOid());
                    //入油數據寫交易賬目
                    dsgAccountTradeService.writeTradingAccounts(dsgBankDetail);
                    returnDsgOilData.setSuccessNum(successNum);
                    returnDsgOilData.setFailNum(failNum);
                    returnDsgOilData.setDoubtANum(doubtANum);
                    returnDsgOilData.setDoubtBNum(doubtBNum);
                    returnDsgOilData.setDoubtCNum(doubtCNum);
                    ajaxResult.setCode(MessageConstants.SSO_STATUS_SUCCESS.getCode());
                    ajaxResult.setData(returnDsgOilData);
                    ajaxResult.setMessage("校驗成功");
                }
            }
        } finally {
            if (CollectionUtil.isNotEmpty(keyList)) {
                keyList.forEach(I -> {
                    leveldbAccess.delete(I);
                });
            }
        }
        return ajaxResult;
    }

    /**
     * 添加存疑记录
     *
     * @param dsgOilDoubtListList 存疑记录集合
     * @param cusNo               客户编号
     * @param colId               入油資料匯總ID
     * @param oilId               入油數據明細ID
     * @param doubtLevel          存疑級別
     * @param doubtCode           存疑編碼
     */
    private void addDsgOilDoubtList(List<DsgOilDoubtList> dsgOilDoubtListList, String cusNo, String colId, String oilId,
                                    String doubtLevel, String doubtCode) {
        DsgOilDoubtList dsgOilDoubtList = new DsgOilDoubtList();
        dsgOilDoubtList.setOid(UUIDGenerator.getUUID());
        dsgOilDoubtList.setCusNo(cusNo);
        dsgOilDoubtList.setColId(colId);
        dsgOilDoubtList.setOilId(oilId);
        dsgOilDoubtList.setDoubtLevel(doubtLevel);
        dsgOilDoubtList.setDoubtCode(doubtCode);
        dsgOilDoubtListList.add(dsgOilDoubtList);
    }

    /**
     * A1系統中設有折扣上/下限，上數客戶所屬折扣超越折扣上/下
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private String checkDoubtA1(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        //系統中設有折扣上/下限，上數客戶所屬折扣超越折扣上/下限
        String doubt = null;
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getProductNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgOilProduct.class.getSimpleName(), dsgOilDataDetail.getProductNo());
            DsgOilProduct dsgOilProduct = leveldbAccess.get(key);
            if (dsgOilProduct == null) {
//                                    errorList.add(String.format("咭號%s車牌號%s產品編號%s的產品不存在！", dsgOilDataDetail.getCardNo(),
//                                            dsgOilDataDetail.getCarNumber(), dsgOilDataDetail.getProductNo()));
            } else {
                //1系統中設有折扣上/下限，上數客戶所屬折扣超越折扣上/下限 TODO
//                doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
//                doubtMap.put("A", doubt);
//                addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "1");
            }
        }
        return doubt;
    }

    /**
     * A2同日期, 同時間 , 同車牌,同 CARD NUMBER 如已於系統存在之數 據則自動拒絕接受 (其餘沒重覆的數據自動錄入至系統中)
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtA2(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        String key = leveldbAccess.genCacheKey(oid, DsgOilDataDetail.class.getSimpleName(),
                dsgOilDataDetail.getTransDate(), dsgOilDataDetail.getTransTime(),
                dsgOilDataDetail.getCarNumber(), dsgOilDataDetail.getCardNo());
        DsgOilDataDetail dodd = leveldbAccess.get(key);
        if (dodd != null) {
            String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
            doubtMap.put("A", doubt);
            this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "2");
        }
    }

    /**
     * A3如 ESSO 數據中的油費為負數
     *
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     * @return
     */
    private void checkDoubtA3(String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (BigDecimal.ZERO.compareTo(dsgOilDataDetail.getOilValue()) > 0) {
            String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
            doubtMap.put("A", doubt);
            this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "3");
        }
    }

    /**
     * A4上數時我司系統中沒有相關油咭號碼之紀錄
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtA4(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        String key = leveldbAccess.genCacheKey(oid, DsgApplyCard.class.getSimpleName(), dsgOilDataDetail.getCardNo());
        List<DsgApplyCard> dsgApplyCardList = leveldbAccess.get(key);
        if (CollectionUtil.isEmpty(dsgApplyCardList)) {
            String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
            doubtMap.put("A", doubt);
            addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "4");
        }
    }

    /**
     * A5我司系統有記錄現時 ESSO 生效中油站數及名稱，如 ESSO 數據中的油站名稱未在系統記錄中，會成為此存疑
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtA5(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getStationId())) {
            String key = leveldbAccess.genCacheKey(oid, DsgOilStation.class.getSimpleName(), dsgOilDataDetail.getStationId());
            DsgOilStation dsgOilStation = leveldbAccess.get(key);
            if (dsgOilStation == null) {
                String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
                doubtMap.put("A", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "5");
            }
        }
    }

    /**
     * A7系統中登記油種與 ESSO 數據客人入油種不同
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtA7(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCarNumber())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyCar.class.getSimpleName(), dsgOilDataDetail.getCarNumber());
            DsgApplyCar dsgApplyCar = leveldbAccess.get(key);
            key = leveldbAccess.genCacheKey(oid, DsgOilProduct.class.getSimpleName(), dsgOilDataDetail.getProductNo());
            DsgOilProduct dsgOilProduct = leveldbAccess.get(key);
            if (dsgApplyCar != null && dsgOilProduct != null) {
                if (dsgApplyCar.getCarOilType().intValue() != dsgOilProduct.getOilType().intValue()) {
                    String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
                    doubtMap.put("A", doubt);
                    this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "7");
                }
            }
        }
    }

    /**
     * A8如 ESSO 數據中所屬客戶的折扣正等待審批，需待完成審批後方能重 新上數
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtA8(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCardNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyDiscount.class.getSimpleName(), dsgOilDataDetail.getCardOid());
            DsgApplyDiscount dsgApplyDiscount = leveldbAccess.get(key);
            if (dsgApplyDiscount == null) {
                String doubt = DsgOilDataDetail.AppStatusChar.A.getCode();
                doubtMap.put("A", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "8");
            }
        }
    }

    /**
     * B1客人戶口結餘超出 10 萬
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB1(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCusNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyCus.class.getSimpleName(), dsgOilDataDetail.getCusNo());
            DsgApplyCus dsgApplyCus = leveldbAccess.get(key);
            if (dsgApplyCus == null) {
            } else {
                if (StringUtil.isNotEmpty(dsgApplyCus.getCusNo())) {
                    key = leveldbAccess.genCacheKey(oid, DsgAccountCus.class.getSimpleName(), dsgApplyCus.getCusNo());
                    DsgAccountCus dsgAccountCus = leveldbAccess.get(key);
                    if (dsgAccountCus != null && dsgAccountCus.getBalanceValue().compareTo(DsgAccountCus.maxBalanceValue) > 0) {
                        String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
                        doubtMap.put("B", doubt);
                        this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "1");
                    }
                }
            }
        }
    }

    /**
     * B2我司系統中客人使用油咭所屬油種折扣為 0
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB2(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCusNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyDiscount.class.getSimpleName(), dsgOilDataDetail.getCusNo());
            DsgApplyDiscount dsgApplyDiscount = leveldbAccess.get(key);
            if (dsgApplyDiscount == null || (dsgApplyDiscount != null &&
                    dsgApplyDiscount.getCheepAmount().intValue() <= 0 &&
                    dsgApplyDiscount.getCostlyAmount().intValue() <= 0)) {
                String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
                doubtMap.put("B", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "2");
            }
        }
    }


    /**
     * B3我司系統中客人行政費為 0%
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB3(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCusNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyCard.class.getSimpleName(), dsgOilDataDetail.getCardNo(), DsgApplyCard.CARD_STATUS_4);
            DsgApplyCard dsgApplyCard = leveldbAccess.get(key);
            if (dsgApplyCard != null && dsgApplyCard.getAdminCost().compareTo(BigDecimal.ZERO) <= 0) {
                String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
                doubtMap.put("B", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "3");
            }
        }
    }

    /**
     * B4上數 ESSO 數據中的油咭號碼於我司系統有兩位或以上客戶擁有 (如有此類情況，會以入油日期時間作準，入油時那個客戶油咭生效中則會成為上數之客戶)
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB4(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCusNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyCard.class.getSimpleName(), dsgOilDataDetail.getCardNo());
            List<DsgApplyCard> dsgApplyCardList = leveldbAccess.get(key);
            if (CollectionUtil.isNotEmpty(dsgApplyCardList) && dsgApplyCardList.size() > 1) {
                List<String> ownsIdList = dsgApplyCardList.stream().map(DsgApplyCard::getCusNo).collect(Collectors.toList());
                long count = ownsIdList.stream().distinct().count();
                if (ownsIdList.size() != count) {
                    String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
                    doubtMap.put("B", doubt);
                    this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "4");
                }
            }
        }
    }

    /**
     * B5pump_unit_price 與 特 定 FORMULA 計算出的結果不符
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB5(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        //油的升數
        BigDecimal oilLiters = dsgOilDataDetail.getOilLiters();
        //油的單價
        BigDecimal oilPrice = dsgOilDataDetail.getOilPrice();
        //油的總價
        BigDecimal oilValue = dsgOilDataDetail.getOilValue();
//        BigDecimal amount, quantity;
        if (oilLiters == null || oilPrice == null || oilValue == null) {
            String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
            doubtMap.put("B", doubt);
            this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "5");
        } else {
            //pump_unit_price=product_value_supplier/quantity
//            amount = oilValue.divide(oilLiters, 4, BigDecimal.ROUND_HALF_UP);
//            if (amount.compareTo(oilPrice) != 0) {
//                quantity = oilValue.divide(oilPrice, BigDecimal.ROUND_HALF_UP);
//            }
        }
    }

    /**
     * B6上數時，上數時不是收正常數據的日子 (超越兩工作天) 提示
     *
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB6(String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (dsgOilDataDetail.getTransDate() != null) {
            if (DateUtils.daysBetween(dsgOilDataDetail.getTransDate(), new Date()) > 2 || DateUtils.daysBetween(dsgOilDataDetail.getTransDate(), new Date()) < 0) {
                String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
                doubtMap.put("B", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "6");
            }
        }
    }

    /**
     * B7如 A2 中的重覆交易的條件中，唯獨升數 有出入的，會掉入此處
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtB7(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        String key = leveldbAccess.genCacheKey(oid, DsgOilDataDetail.class.getSimpleName(),
                dsgOilDataDetail.getTransDate(), dsgOilDataDetail.getTransTime(),
                dsgOilDataDetail.getCarNumber(), dsgOilDataDetail.getCardNo());
        DsgOilDataDetail dodd = leveldbAccess.get(key);
        if (dodd != null && StringUtil.isNotEmpty(dodd.getOilLitersList()) && dodd.getOilLitersList().split(",").length > 1) {
            String doubt = DsgOilDataDetail.AppStatusChar.B.getCode();
            doubtMap.put("B", doubt);
            this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "7");
        }
    }

    /**
     * C1如上數 ESSO 數據中的油咭不是生效中，需檢查存疑
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtC1(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCardNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyCard.class.getSimpleName(), dsgOilDataDetail.getCardNo(), DsgApplyCard.AppStatus.inForce.getCode());
            DsgApplyCard dsgApplyCard = leveldbAccess.get(key);
            if (dsgApplyCard == null) {
                String doubt = DsgOilDataDetail.AppStatusChar.C.getCode();
                doubtMap.put("C", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "1");
            }
        }
    }

    /**
     * C2如上數 ESSO 數據中的油咭所屬客戶狀況不是生效中，需檢查存疑
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtC2(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCardNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgApplyCus.class.getSimpleName(), dsgOilDataDetail.getCusNo());
            DsgApplyCus dsgApplyCus = leveldbAccess.get(key);
            if (dsgApplyCus != null && !DsgApplyCus.AppStatus.inForce.getCode().equals(dsgApplyCus.getCusType())) {
                String doubt = DsgOilDataDetail.AppStatusChar.C.getCode();
                doubtMap.put("C", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "2");
            }
        }
    }

    /**
     * C3如油站數目與系統中生效中油站不乎，需檢查
     *
     * @param oid              緩存OID
     * @param colId            入油匯總OID
     * @param doubtMap         存疑
     * @param dsgOilDataDetail 入油明細數據
     * @param doubtList        存疑记录
     */
    private void checkDoubtC3(String oid, String colId, Map<String, String> doubtMap, DsgOilDataDetail dsgOilDataDetail, List<DsgOilDoubtList> doubtList) {
        if (StringUtil.isNotEmpty(dsgOilDataDetail.getCardNo())) {
            String key = leveldbAccess.genCacheKey(oid, DsgOilStation.class.getSimpleName(), dsgOilDataDetail.getStationId());
            DsgOilStation dsgOilStation = leveldbAccess.get(key);
            if (dsgOilStation != null && !DsgOilStation.AppStatus.takeEffect.getCode().equals(dsgOilStation.getStationStatus())) {
                String doubt = DsgOilDataDetail.AppStatusChar.C.getCode();
                doubtMap.put("C", doubt);
                this.addDsgOilDoubtList(doubtList, dsgOilDataDetail.getCusNo(), colId, dsgOilDataDetail.getOid(), doubt, "3");
            }
        }
    }

}
